#include <lversion.h>
#if L_VERSION_MODULE_TRI_MESH == 111227

#include "_ltriMesh_111227.h"

using namespace llib;

#include <map>
using std::pair;
using std::map;

geom::TriMesh::TriMesh()
{
    _vertexNum = _edgeNum = _faceNum = 0;
    _vertexList = NULL;
    _edgeVertexIndexList = _edgeFaceIndexList = NULL;
    _faceVertexIndexList = _faceEdgeIndexList = NULL;
    _modelBuild = FALSE;
}

geom::TriMesh::TriMesh( std::vector<Vec3f>& vertexList, std::vector<Vec3i>& faceVertexIndexList ) : _modelBuild(FALSE)
{
    BOOST_ASSERT(SZ(vertexList) > 0);
    BOOST_ASSERT(SZ(faceVertexIndexList) > 0);
    resetModelData(vertexList, faceVertexIndexList);
}

geom::TriMesh::TriMesh( const TriMesh& m ) : _modelBuild(FALSE)
{
    modelCopy(m);
}

geom::TriMesh::~TriMesh()
{
    delete[] _vertexList;
    delete[] _faceVertexIndexList;
    delete[] _faceEdgeIndexList;
    delete[] _edgeVertexIndexList;
    delete[] _edgeFaceIndexList;
}

geom::TriMesh& geom::TriMesh::operator=( const geom::TriMesh& m )
{
    modelCopy(m);
    return *this;
}

void geom::TriMesh::SetModelData( std::vector<Vec3f>& vertexList, std::vector<Vec3i>& faceVertexIndexList )
{
    BOOST_ASSERT(SZ(vertexList) > 0);
    BOOST_ASSERT(SZ(faceVertexIndexList) > 0);
    resetModelData(vertexList, faceVertexIndexList);
}

geom::MeshVertex geom::TriMesh::GetVertex( Int32 index ) const
{
    return MeshVertex((TriMesh*)this, index);
}

geom::MeshEdge geom::TriMesh::GetEdge( Int32 index ) const
{
    return MeshEdge((TriMesh*)this, index);
}

geom::MeshFace geom::TriMesh::GetFace( Int32 index ) const
{
    return MeshFace((TriMesh*)this, index);
}

void geom::TriMesh::resetModelData( std::vector<Vec3f>& vertexList, std::vector<Vec3i>& faceVertexIndexList )
{
    {
    // remove old data when necessary
    if(_modelBuild) {
        delete[] _vertexList;
        delete[] _faceVertexIndexList;
        delete[] _faceEdgeIndexList;
        delete[] _edgeVertexIndexList;
        delete[] _edgeFaceIndexList;
    }
    }

    {
    // copy vertex list
    _vertexNum  = SZ(vertexList);
    _vertexList = new Vec3f[_vertexNum];
    FOR(I,0,_vertexNum) _vertexList[I] = vertexList[I];
    }

    {
    // copy face-vertex index list
    _faceNum    = SZ(faceVertexIndexList);
    _faceVertexIndexList = new Vec3i[_faceNum];
    FOR(I,0,_faceNum) _faceVertexIndexList[I] = faceVertexIndexList[I];
    // and init face-edge index list
    _faceEdgeIndexList = new Vec3i[_faceNum];
    FOR(I,0,_faceNum) FOR(J,0,3) _faceEdgeIndexList[I][J] = _invalidIndex;
    }

    {
    // generate edges and relations
    typedef pair<Int32,Int32>               EdgePair;
    typedef pair<Int32,MeshFace::EdgeName>  FaceInfo;
    typedef pair<FaceInfo,FaceInfo>         FacePair;
    const static MeshFace::EdgeName EdgeTypes[3] = { MeshFace::EdgeAB, MeshFace::EdgeBC, MeshFace::EdgeCA };
    const static Int32 VertexIndex[3][2] = { { 0, 1 }, { 1, 2 }, { 2, 0 } };
    // here edgeMap is a collection collects edge info (a little more complicated)
    // EdgePair : (VertexIndexBegin, VertexIndexEnd)    : where VertexIndexBegin < VertexIndexEnd
    // FaceInfo : (FaceIndex, current edge type of current face)
    // FacePair : (FaceIndexLeft, FaceIndexRight)
    // EdgePair -> FacePair <==>
    //     (VertexIndexBegin, VertexIndexEnd) -> ( (FaceIndexLeft, EdgeType of LeftFace), (FaceIndexRight, EdgeType of RightFace) )
    map<EdgePair,FacePair> edgeMap;
    EdgePair tmpKey;
    FacePair tmpVal;
    FOR(F,0,_faceNum) {
        Vec3i& faceVertexIndex = _faceVertexIndexList[F];
        FOR(E,0,3) {
            Int32 vertexIndexBegin  = faceVertexIndex[ VertexIndex[E][0] ];
            Int32 vertexIndexEnd    = faceVertexIndex[ VertexIndex[E][1] ];
            Boolean directionForward = (vertexIndexBegin < vertexIndexEnd);
            tmpKey.first   = vertexIndexBegin;
            tmpKey.second  = vertexIndexEnd;
            if(!directionForward) std::swap(tmpKey.first,tmpKey.second);
            map<EdgePair,FacePair>::iterator iter = edgeMap.find(tmpKey);
            if(iter != edgeMap.end()) {
                tmpVal = iter->second;
            } else {
                tmpVal.first.first  = _invalidIndex;
                tmpVal.second.first = _invalidIndex;
            }
            if(directionForward) {
                tmpVal.first.first  = F;
                tmpVal.first.second = EdgeTypes[E];
            } else {
                tmpVal.second.first = F;
                tmpVal.second.second= EdgeTypes[E];
            }
            edgeMap[ tmpKey ] = tmpVal;
        }
    }
    // edge collection finished
    // generate edge-vertex/edge-face index lists
    _edgeNum = SZ(edgeMap);
    _edgeVertexIndexList = new Vec2i[_edgeNum];
    _edgeFaceIndexList   = new Vec2i[_edgeNum];
    Int32 index = 0;
    for(map<EdgePair,FacePair>::iterator iter = edgeMap.begin();
        iter != edgeMap.end(); ++iter, ++index) {
        Vec2i& edgeVertexIndex  = _edgeVertexIndexList[index];
        Vec2i& edgeFaceIndex    = _edgeFaceIndexList[index];
        const Int32& vertexIndexBegin = iter->first.first;
        const Int32& vertexIndexEnd   = iter->first.second;
        Int32& faceIndexLeft    = iter->second.first.first;
        Int32& faceIndexRight   = iter->second.second.first;
        MeshFace::EdgeName& edgeTypeLeft  = iter->second.first.second;
        MeshFace::EdgeName& edgeTypeRight = iter->second.second.second;

        edgeVertexIndex[0]      = vertexIndexBegin;
        edgeVertexIndex[1]      = vertexIndexEnd;
        edgeFaceIndex[0]        = faceIndexLeft;
        edgeFaceIndex[1]        = faceIndexRight;

        if(faceIndexLeft != _invalidIndex) {
            Vec3i& leftFaceEdgeIndex = _faceEdgeIndexList[faceIndexLeft];
            leftFaceEdgeIndex[Int32(edgeTypeLeft)] = index;
        }
        if(faceIndexRight != _invalidIndex) {
            Vec3i& rightFaceEdgeIndex = _faceEdgeIndexList[faceIndexRight];
            rightFaceEdgeIndex[Int32(edgeTypeRight)] = index;
        }
    }
    }

    // all done, set flag
    _modelBuild = TRUE;
}

void geom::TriMesh::modelCopy( const TriMesh& m )
{
    if(!m._modelBuild) {
        if(_modelBuild) {
            delete[] _vertexList;
            delete[] _faceVertexIndexList;
            delete[] _faceEdgeIndexList;
            delete[] _edgeVertexIndexList;
            delete[] _edgeFaceIndexList;
        }
        _vertexNum = _edgeNum = _faceNum = 0;
        _vertexList = NULL;
        _edgeVertexIndexList = _edgeFaceIndexList = NULL;
        _faceVertexIndexList = _faceEdgeIndexList = NULL;
        _modelBuild = FALSE;
        return;
    }

    // prepare heap memory
    if(_modelBuild) {
        // vertex
        if(_vertexNum != m._vertexNum) {
            _vertexNum = m._vertexNum;
            delete[] _vertexList;
            _vertexList = new Vec3f[_vertexNum];
        }
        // edge
        if(_edgeNum != m._edgeNum) {
            _edgeNum = m._edgeNum;
            delete[] _edgeVertexIndexList;
            delete[] _edgeFaceIndexList;
            _edgeVertexIndexList = new Vec2i[_edgeNum];
            _edgeFaceIndexList = new Vec2i[_edgeNum];
        }
        // face
        if(_faceNum != m._faceNum) {
            _faceNum = m._faceNum;
            delete[] _faceVertexIndexList;
            delete[] _faceEdgeIndexList;
            _faceVertexIndexList = new Vec3i[_faceNum];
            _faceEdgeIndexList = new Vec3i[_faceNum];
        }
    } else {
        _vertexNum              = m._vertexNum;
        _edgeNum                = m._edgeNum;
        _faceNum                = m._faceNum;
        _vertexList             = new Vec3f[_vertexNum];
        _edgeVertexIndexList    = new Vec2i[_edgeNum];
        _edgeFaceIndexList      = new Vec2i[_edgeNum];
        _faceVertexIndexList    = new Vec3i[_faceNum];
        _faceEdgeIndexList      = new Vec3i[_faceNum];
    }

    // deep copy
    FOR(v,0,_vertexNum) {
        _vertexList[v] = m._vertexList[v];
    }
    FOR(e,0,_edgeNum) {
        _edgeVertexIndexList[e] = m._edgeVertexIndexList[e];
        _edgeFaceIndexList[e]   = m._edgeFaceIndexList[e];
    }
    FOR(f,0,_faceNum) {
        _faceVertexIndexList[f] = m._faceVertexIndexList[f];
        _faceEdgeIndexList[f]   = m._faceEdgeIndexList[f];
    }

    // all done, set flag
    _modelBuild = TRUE;
}

geom::MeshVertex geom::MeshEdge::GetVertex( const VertexName name ) const
{
    Int32 vertexNameNum = (Int32)name;
    return GetVertex(vertexNameNum);
}

geom::MeshVertex geom::MeshEdge::GetVertex( const Int32 name ) const
{
    BOOST_ASSERT(Valid());
    BOOST_ASSERT(name == 0 || name == 1);
    Int32 vertexIndex = _mesh->_edgeVertexIndexList[_index][name];
    if(vertexIndex != TriMesh::_invalidIndex)
        return MeshVertex(_mesh,vertexIndex);
    else
        return MeshVertex(); // return an invalid edge
}

geom::MeshFace geom::MeshEdge::GetFace( const FaceName name ) const
{
    Int32 faceNameNum = (Int32)name;
    return GetFace(faceNameNum);
}

geom::MeshFace geom::MeshEdge::GetFace( const Int32 name ) const
{
    BOOST_ASSERT(Valid());
    BOOST_ASSERT(name == 0 || name == 1);
    Int32 faceIndex = _mesh->_edgeFaceIndexList[_index][name];
    if(faceIndex != TriMesh::_invalidIndex)
        return MeshFace(_mesh, faceIndex);
    else
        return MeshFace(); // return a invalid face
}

geom::MeshVertex geom::MeshFace::GetVertex( const VertexName name ) const
{
    Int32 vertexNameNum = (Int32)name;
    return GetVertex(vertexNameNum);
}

geom::MeshVertex geom::MeshFace::GetVertex( const Int32 name ) const
{
    BOOST_ASSERT(Valid());
    BOOST_ASSERT(name == 0 || name == 1 || name == 2);
    Int32 vertexIndex = _mesh->_faceVertexIndexList[_index][name];
    if(vertexIndex != TriMesh::_invalidIndex)
        return MeshVertex(_mesh, vertexIndex);
    else
        return MeshVertex();
}

geom::MeshEdge geom::MeshFace::GetEdge( const EdgeName name ) const
{
    Int32 edgeNameNum = (Int32)name;
    return GetEdge(edgeNameNum);
}

geom::MeshEdge geom::MeshFace::GetEdge( const Int32 name ) const
{
    BOOST_ASSERT(Valid());
    BOOST_ASSERT(name == 0 || name == 1 || name == 2);
    Int32 edgeIndex = _mesh->_faceEdgeIndexList[_index][name];
    if(edgeIndex != TriMesh::_invalidIndex)
        return MeshEdge(_mesh, edgeIndex);
    else
        return MeshEdge();
}

geom::Tri3f geom::MeshFace::GetTriangle() const
{
    BOOST_ASSERT(Valid());
    Vec3i& vertexIndex = _mesh->_faceVertexIndexList[_index];
    Vec3f& vA = _mesh->_vertexList[ vertexIndex[0] ];
    Vec3f& vB = _mesh->_vertexList[ vertexIndex[1] ];
    Vec3f& vC = _mesh->_vertexList[ vertexIndex[2] ];
    return Tri3f(vA, vB, vC);
}

geom::Vec3f geom::MeshFace::GetNormal() const
{
    BOOST_ASSERT(Valid());
    Vec3i& vertexIndex = _mesh->_faceVertexIndexList[_index];
    Vec3f& vA = _mesh->_vertexList[ vertexIndex[0] ];
    Vec3f& vB = _mesh->_vertexList[ vertexIndex[1] ];
    Vec3f& vC = _mesh->_vertexList[ vertexIndex[2] ];
    Vec3f v1 = vC - vA;
    Vec3f v2 = vB - vA;
    Vec3f res = v1.Cross(v2);
    res.Normalize();
    return res;
}

Boolean geom::MeshFace::CheckNeighbour( const MeshFace& first, const MeshFace& second )
{
    Vec3i& vid0 = first._mesh->_faceVertexIndexList[first._index];
    Vec3i& vid1 = second._mesh->_faceVertexIndexList[second._index];
    return vid0.x == vid1.x || vid0.x == vid1.y || vid0.x == vid1.z ||
           vid0.y == vid1.x || vid0.y == vid1.y || vid0.y == vid1.z ||
           vid0.z == vid1.x || vid0.z == vid1.y || vid0.z == vid1.z;
}


#endif
